package tpdisenio2009.mvp.presenter;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import tpdisenio2009.Tpdisenio2009App;
import tpdisenio2009.model.beans.RealTeam;
import tpdisenio2009.model.beans.Score;
import tpdisenio2009.model.beans.SoccerMatch;
import tpdisenio2009.model.beans.SoccerPlayer;
import tpdisenio2009.model.beans.TournamentDate;
import tpdisenio2009.mvp.display.ManageTournamentDatePointsView;
import tpdisenio2009.services.SoccerMatchService;
import tpdisenio2009.services.TournamentDatePointsService;
import tpdisenio2009.services.TournamentDateService;

/**
 *
 * @author Nicolás Kreiff
 */
public class ManageTournamentDatePointsPresenter extends DefaultPresenter<ManageTournamentDatePointsView> {

    private final TournamentDatePointsService service;
    private final SoccerMatchService matchService;
    private final TournamentDateService tdService;

    private ActionListener dateChangedListener;
    private ActionListener showDetailsListener;
    private ListSelectionListener playerSelectionListener;
    private ActionListener saveListener;
    private ActionListener closeListener;

    public ManageTournamentDatePointsPresenter( ManageTournamentDatePointsView view ) {
        super( view );

        service = new TournamentDatePointsService();
        matchService = new SoccerMatchService();
        tdService = new TournamentDateService();

        List<TournamentDate> dates = service.getAssignableDates();
        getView().setDates( dates );
        getView().setFirstOpenDate( tdService.getFirstOpenTournamentDate() );
        getView().loadMatchs( matchService.getSoccerMatchByTournamentDate( getView().getDate() ) );
        getView().hidePoints();

        if (dates == null || dates.size() == 0) {
            getView().showError( "No existen fechas cerradas o en período de veda a las cuales asignar o consultar los puntos", "Error: No existen fechas..." );
        } else
            bind();
    }

    public void bind() {
        dateChangedListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if( getView().getDate().getState().equals( TournamentDate.CLOSED_DATE ) ) {
                    getView().disableMatchTable();
                    getView().disableHomeTable();
                    getView().disableVisitorTable();
                    getView().showOK("<html>La fecha " + getView().getDate().toString() + " esta cerrada.<br>No es posible editarla.</html>", "Fecha cerrada");
                } else {
                    getView().enableMatchTable();
                    getView().enableHomeTable();
                    getView().enableVisitorTable();
                }
                getView().loadMatchs( matchService.getSoccerMatchByTournamentDate( getView().getDate() ) );
                getView().hidePoints();
            }
        };
        getView().addDateChangeListener( dateChangedListener );

        getView().addStateChangedListener(saveListener);

        showDetailsListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showDetails();
            }
        };
        getView().addShowDetailsListener(showDetailsListener);

        playerSelectionListener = new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                playerSelectionChanged();
            }
        };
        getView().addPlayerSelectionListener(playerSelectionListener);

        saveListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                save();
            }
        };
        getView().addSaveListener(saveListener);

        closeListener = new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if( showConfirmation() ) {
                    Tpdisenio2009App.loggedUser = null;
                    System.exit(0);
                }
            }
        };
        getView().addCloseSessionListener(closeListener);
    }

    public void unbind() {
        if (dateChangedListener != null)
            getView().removeDateChangeListener(dateChangedListener);
        if (showDetailsListener != null)
            getView().removeShowDetailsListener(showDetailsListener);
        if (playerSelectionListener != null)
            getView().removePlayerSelectionListener(playerSelectionListener);
        if (saveListener != null)
            getView().removeSaveListener(saveListener);
        if (saveListener != null)
            getView().removeCloseSessionListener(closeListener);
    }

    // PRIVATE METHODS ---------------------------------------------------------

    private void showDetails() {
        SoccerMatch match = getView().getSelectedMatch();

        RealTeam localTeam;
        RealTeam visitorTeam;
        if( match != null ) {
            localTeam = match.getRealTeamLocal();
            visitorTeam = match.getRealTeamVisitor();        

            getView().setLocalTeamName( localTeam.getName() );
            getView().setVisitorTeamName( visitorTeam.getName() );

            List<SoccerPlayer> localSoccerPlayers = new LinkedList<SoccerPlayer>();
            localSoccerPlayers.addAll( localTeam.getSosserPlayerCollection() );
            getView().loadLocalPlayers( localSoccerPlayers );

            List<SoccerPlayer> visitorSoccerPlayers = new LinkedList<SoccerPlayer>();
            visitorSoccerPlayers.addAll( visitorTeam.getSosserPlayerCollection() );
            getView().loadVisitorPlayers( visitorSoccerPlayers );

            getView().hidePoints();
            getView().setFirstPlayerSelected();
        } else {
            getView().showError("Debe seleccionar previamente un partido.", "Error: Partido no seleccionado.");
        }
    }

    private void playerSelectionChanged() {
        TournamentDate date = getView().getDate();
        SoccerPlayer player = getView().getSelectedPlayer();

        if (player == null)
            return;
        
        Collection<Score> scores = player.getScoreCollection();

        if (scores == null || scores.size() == 0) {
            getView().setPlayerScore( null );
            return;
        }

        for (Score score : scores)
            if (date.equals( score.getTournamentDate() )) {
                getView().showPoints();
                getView().setPlayerScore( score );
                break;
            }
    }

    private void save() {
        List<SoccerMatch> matchs = getView().getMatchs();
        Collection<Score> updatedScores = getView().getUpdatedScores();

        // Validar -------------------------------------------------------------

        for (SoccerMatch match : matchs) {
            int figurasLocal = 0, figurasVisitante = 0;
            int golesLocal = 0, golesVisitante = 0;
            int golesRecibidosLocal = 0, golesRecibidosVisitante = 0;
            int golesEnContraLocal = 0, golesEnContraVisitante = 0;
            for (Score score : updatedScores) {
                if (score.getTournamentDate().equals( match.getTournamentDate() )) {
                    if (score.getSoccerPlayer().getRealTeam().equals( match.getRealTeamLocal() )) {
                        golesLocal += score.getGoals();
                        golesRecibidosLocal += score.getReceivedGoals();
                        golesEnContraLocal += score.getOwnGoals();
                        if (score.getFigure())
                            figurasLocal++;

                    } else if (score.getSoccerPlayer().getRealTeam().equals( match.getRealTeamVisitor() )) {
                        golesVisitante += score.getGoals();
                        golesRecibidosVisitante += score.getReceivedGoals();
                        golesEnContraVisitante += score.getOwnGoals();
                        if (score.getFigure())
                            figurasVisitante++;
                    }
                }
            }
            if (golesLocal != golesRecibidosVisitante || golesVisitante != golesRecibidosLocal) {
                getView().showError( "La cantidad de goles convertidos por un equipo deben ser igual a la cantidad de goles recibidos por el otro equipo", "Cantidad de goles inconsistentes..." );
                return;
            }
            if (golesEnContraLocal > golesRecibidosLocal || golesEnContraVisitante > golesRecibidosVisitante) {
                getView().showError( "La cantidad de goles en contra de un equipo debe ser menor o igual a la cantidad de goles que ha recibido...", "Cantidad de goles inconsistente..." );
                return;
            }
            if (figurasLocal > 1 || figurasVisitante > 1) {
                getView().showError( "Los equipos deben poseer una unica figura", "Cantidad de figuras inconsistente..." );
            }
        }

        // Salvar todo ---------------------------------------------------------

        for (SoccerMatch match : matchs)
            matchService.updateSoccerMatchState( match.getId(), match.getState() );

        for (Score score : updatedScores)
            if (score.getId() == null)
                service.insert( score );
            else
                service.update( score );
    }

    private boolean showConfirmation() {
        return getView().showConfirmation( "¿Está seguro que desea cerrar la sesión?"  );
    }
}
